#include "laurin-module.h"
#include <sched.h>

LaurinModule::LaurinModule(const Glib::ustring& moduleName)
{
	if(!Glib::thread_supported())
		Glib::thread_init();

	_moduleName = Glib::ustring(moduleName);
	_id = new Glib::Quark(moduleName);

	_thread = NULL;
	_active = false;			// thread not created

	_wakeup = false;
	_exit = false;
	_working = false;
	_stopRequest = false;
}


LaurinModule::~LaurinModule()
{
	// operation must be terminated on the subclass
	// so call join() is safe

	delete _id;

	_signal.clear();

	_exit = true;
	stop(true);
	wakeup();
	_thread->join();

}



void LaurinModule::wait()
{
	//TODO check.
	// the purpose it to allow other module thread to reach this point before the current
	// thread go on run.
	sched_yield();

	while(!_exit)
	{

		// wait
		_mutex.lock();

		while(!_wakeup)
			_wait.wait(_mutex);


		_mutex.unlock();


		// do work
		if(!_exit)
		{
			_mutex.lock();
			_wakeup = false;
			_working = true;
			_stopRequest = false;
			_mutex.unlock();

			run();

			_signal.emit();

			_mutex.lock();
			_working = false;
			_stopWait.signal();
			_mutex.unlock();
		}
	}
}


void LaurinModule::wakeup()
{

	_mutex.lock();
	_wakeup = true;
	_wait.signal();
	_mutex.unlock();

}


void LaurinModule::setActive()
{
	// this method only defers the creation of the thread
	// thread is created only when start() is called.

	if(!_active)
	{
		_active = true;
		_wakeup = true;

		// thread is joinable
		_thread = Glib::Thread::create(sigc::mem_fun(*this, &LaurinModule::wait), true);
	}
	else
		wakeup();
}


void LaurinModule::start()
{
	if(isWorking())
		return;

	// create thread if not alredy created
	setActive();
}


void LaurinModule::stop(bool wait)
{

	if(!isWorking())
		return;


	_mutex.lock();
	// I can't lose the signal isWorking is setted to false only when the signal is raised
	_stopRequest = true;
	_mutex.unlock();


	innerStop();


	if(wait)
	{
		_mutex.lock();
		while(_working)
			_stopWait.wait(_mutex);

		_mutex.unlock();
	}
}


bool LaurinModule::isStopRequestPending()
{
	bool rs = false;
	_mutex.lock();
	rs = _stopRequest;
	_mutex.unlock();

	return rs;
}


bool LaurinModule::isWorking()
{
	bool rs = false;
	_mutex.lock();
	rs = _working;
	_mutex.unlock();

	return rs;
}


void LaurinModule::registerOperationCompletedCallback(sigc::slot<void> callback)
{
	_signal.connect(callback);
}


Glib::ustring LaurinModule::getModuleName() const
{
	return _moduleName;
}


bool LaurinModule::operator=(const LaurinModule& op)
{
	return (*_id) == *(op._id);

}


void LaurinModule::innerStop(){}
